#include "./list.h"

static
void mds_list_push_first( mds_list *list, mds_node *node )
{
	assert( NULL == list->head );
	assert( NULL == list->tail );
	assert( 1 == list->size );
	list->head = list->tail = node;
}

void mds_list_push_back_( mds_list *list, mds_node *node )
{
	assert( list );
	assert( node );
	assert( NULL == node->next );
	assert( NULL == node->prev );
	assert( ! mds_list_owns_(list,node) );
	
	switch( list->size++ )
	{
		case 0:
			mds_list_push_first( list, node );
			break;
			
		default:
		{
			mds_node *tail = list->tail;
			assert( NULL != list->head );
			assert( NULL == list->head->prev );
			
			assert( NULL != list->tail );
			assert( NULL == list->tail->next );
			node->prev = tail;
			tail->next = node;
			list->tail = node;
		}	
			break;
	}
	
	
}


void mds_list_push_front_( mds_list *list, mds_node *node )
{
	assert( list );
	assert( node );
	assert( NULL == node->next );
	assert( NULL == node->prev );
	assert( ! mds_list_owns_(list,node) );
	
	switch( list->size++ )
	{
		case 0:
			mds_list_push_first( list, node );
			break;
			
		default:
		{
			mds_node *head = list->head;
			assert( NULL != list->head );
			assert( NULL == list->head->prev );
			
			assert( NULL != list->tail );
			assert( NULL == list->tail->next );
			node->next = head;
			head->prev = node;
			list->head = node;
		}	
			break;
	}
	
}


int mds_list_owns_( const mds_list *list, const mds_node *node )
{
	assert( list );
	assert( node );
	
	{
		const mds_node *p = list->head;
		while( p )
		{
			if( p == node ) return 1;
			p = p->next;
		}
	}
	
	
	return 0;
}


static
mds_node *mds_list_pop_last( mds_list *list )
{
	mds_node *node = list->head;
	assert( list->head != NULL );
	assert( list->tail != NULL );
	assert( list->head == list->tail );
	assert( 1 == list->size    );
	assert( NULL == node->next );
	assert( NULL == node->prev );
	
	list->tail = list->head = NULL;
	list->size = 0;
	
	return node;
}


mds_node *mds_list_pop_back_( mds_list *list )
{
	assert( list != NULL );
	assert( list->size > 0 );
	
	switch( list->size )
	{
			
		case 1:
			return mds_list_pop_last(list);
			
		default:
		{	
			mds_node *node = list->tail;
			
			assert( list->size > 1 );
			assert( NULL != list->head );
			assert( NULL == list->head->prev );
			
			assert( NULL != list->tail );
			assert( NULL == list->tail->next );
			
			--(list->size);
			
			list->tail       = list->tail->prev;
			list->tail->next = NULL;
			node->prev       = NULL;
			assert( NULL == node->next );
			
			return node;
		}
	}
	
}

mds_node *mds_list_pop_front_( mds_list *list )
{
	
	assert( list != NULL );
	assert( list->size > 0 );
	
	switch( list->size )
	{
		case 1:
			return mds_list_pop_last(list);
			
		default:
		{	
			mds_node *node = list->head;
			
			assert( list->size > 0 );
			assert( NULL != list->head );
			assert( NULL == list->head->prev );
			
			assert( NULL != list->tail );
			assert( NULL == list->tail->next );
			
			--(list->size);
			
			list->head       = list->head->next;
			list->head->prev = NULL;
			node->next       = NULL;
			assert( NULL == node->prev );
			return node;
		}
	}
	
}

mds_node *mds_list_unlink_( mds_list *list, mds_node *node )
{
	assert( list != NULL );
	assert( list->size > 0 );
	assert( node != NULL );
	assert( mds_list_owns_( list, node ) );
	
	if( node == list->head )
	{
		return mds_list_pop_front_( list );
	}
	else
	{
		if( node == list->tail )
		{
			return mds_list_pop_back_( list );
		}
		else
		{
			mds_node *next = node->next;
			mds_node *prev = node->prev;
			
			assert( next != NULL );
			assert( prev != NULL );
			assert( list->size > 2 );
			
			next->prev  = prev;
			prev->next  = next;
			
			--(list->size);
			
			node->next = node->prev = NULL;
			return node;
		}
	}
	
}



